<?php


namespace app\admin\library\builder;


use app\admin\library\builder\components\Form;
use app\admin\library\builder\components\Table;
use think\App;
use think\Container;
use think\Exception;
use think\facade\Response;
use think\Request;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Spyc;
use Twig\TwigFunction;
use app\admin\library\builder\components\Layout as LayoutComponent;
use app\admin\library\builder\components\Search;
use app\admin\library\builder\ext\Twig;

class Layout implements LayoutInterface
{
    /**
     * @var App
     */
    protected $app;

    /**
     * @var Environment
     */
    protected $template;

    /**
     * @var Request
     */
    protected $request;

    /**
     * 共享变量列表
     * @var array
     */
    protected $vars = [];


    /**
     * 模板目录
     * @var $tpl_path
     */
    protected $tpl_path;


    protected $classPath = [
    ];

    /**
     * 组件ID
     * @var KeyManager
     */
    protected $keys;

    /**
     * @var $config
     */
    protected $config;


    /**
     * 控件列表
     * @var array
     */
    protected $components = [];

    public function __construct()
    {
        $this->app = Container::get('app');
        $this->request = $this->app->request;
        $this->classPath = [
            'form'=>Form::class,
            'table'=>Table::class,
            'search'=>Search::class,
            'container'=>components\Container::class
        ];
        $this->tpl_path = __DIR__ . '/tpl/';
        $this->keys = new KeyManager();
        $this->config = Spyc::YAMLLoad(__DIR__ . '/../../config.yml');
    }


    /**
     * 获得当前控制器
     * @return string
     */
    protected function getController()
    {
        return strtolower($this->request->controller()) . '/' . $this->request->action();
    }


    /**
     * 添加组件
     * @param string $component
     * @param array  $components
     *
     * @throws \Exception
     */
    public function pushComponents(string $component, array $components)
    {
        if (!array_key_exists($component, $this->classPath)) {
            throw new \Exception("尚未支持的类型：[{$component}]");
        }
        $obj = new $this->classPath[$component]($components);
        $obj->addkey($this->keys);
        $this->components[] = $obj;

        return $obj->key;
    }

    /**
     * 添加组件
     * @param Components $obj
     */
    public function push(Components $obj)
    {
        $obj->addkey($this->keys);
        $this->components[] = $obj;

        return $obj->key;
    }


    /**
     * 共享变量
     * @param      $key
     * @param null $value
     * @param bool $replace
     */
    public function share($key, $value = null, $replace = false)
    {
        if (is_array($key)) {
            if ($value) {
                $this->vars = $key;
            } else {
                $this->vars = array_merge($this->vars, $key);
            }
        } else {
            $this->vars[$key] = $value;
        }
    }


    /**
     * twig初始化
     * @param array $templates
     */
    private function renderTwig($templates = [])
    {
        foreach ($this->components as $component) {
            $templates[$component->name] = $component->render();
        }
        $loader = new ArrayLoader($templates);

        $this->template = new Environment($loader, [
            'cache'=>false
        ]);

        $this->template->addExtension(new Twig($this->config));

        $this->template->addGlobal('current_url', url());


        $vue_view = '';
        foreach ($this->components as $item) {
            $componentName = $item->name;
            $vue_view .= '<json name="' . $item->key . '">' . json_encode($item->vars) . '</json>';
            $vue_view .= $this->template->render($componentName, $item->vars);
        }

        return $vue_view;
    }


    /**
     * 请求拦截
     */
    private function httpMiddleware()
    {
        foreach ($this->components as $component) {
            if ($this->request->isAjax() && !$this->request->isPjax()) {
                if ($this->request->header('x-response')) {
                    $xtype = $this->request->header('x-response');
                    $type = [
                        'form'=>'callback',
                        'table'=>'load'
                    ];
                    if (isset($type[$xtype]) && isset($component->vars[$type[$xtype]])) {
                        $result = call_user_func_array($component->vars[$type[$xtype]], [
                            function ($msg) {
                                return json($msg, 200);
                            },
                            function ($msg) {
                                return json(['error'=>$msg], 200);
                            }
                        ]);

                        return $result;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 开始渲染
     */
    public function render()
    {
        $debug = $this->app->isDebug();
        $version = $_SERVER['REQUEST_TIME'];

        $type_name = $this->getController();

        if ($result = $this->httpMiddleware()) {
            return $result;
        }

        // $menus = require(__DIR__ . '/../../menu.php');

        $dataType = $this->request->header('x-pjax');
        if ($dataType) {
            return Response::create($this->renderTwig());
        }

        if (!is_file($this->tpl_path . 'layout.twig')) {
            throw new Exception('layout.twig文件不存在');
        }

        $vue_view = $this->renderTwig([
            'layout'=>(new LayoutComponent($this->keys, []))->render()
        ]);

        return $this->template->render('layout', [
            'vue_view'=>$vue_view,
            'menus'=>$this->config
        ]);
    }


    /**
     * 获取替换值
     * @param $key
     *
     * @return mixed
     */
    protected function replace($key)
    {
        return $this->app->config('template.tpl_replace_string')[$key];
    }

//    /**
//     * @throws \ReflectionException
//     */
//    private function build()
//    {
//        $tpl = $this->getTplContent((new \ReflectionClass($this))->getShortName(), true);
//        var_dump($tpl);
//    }

}
